﻿#pragma once
#include <minwindef.h>
#include <stringapiset.h>
#include <string>
#include <AutoFree.h>

class Convert
{
public:
	static __forceinline char *W2A(const wchar_t *STR)
	{
		int size = WideCharToMultiByte(CP_ACP, 0, STR, -1, NULL, 0, NULL, FALSE);
		char *str = new char[sizeof(char) * size];
		WideCharToMultiByte(CP_ACP, 0, STR, -1, str, size, NULL, FALSE);
		return str;
	}

	static __inline char *W2A(const std::wstring &wstr)
	{
		return Convert::W2A(wstr.c_str());
	}

	static __inline std::string W2AS(const std::wstring &wstr)
	{
		return Convert::W2AS(wstr.c_str());
	}

	static __inline std::string W2AS(wchar_t *wstr)
	{
		AutoFree<char> c = W2A(wstr);
		std::string s(c);
		return s;
	}

	static __forceinline wchar_t *A2W(const char *_char)
	{
		int size = MultiByteToWideChar(CP_ACP, 0, _char, strlen(_char) + 1, NULL, 0);
		wchar_t *tchar = new wchar_t[sizeof(wchar_t) * size];
		MultiByteToWideChar(CP_ACP, 0, _char, strlen(_char) + 1, tchar, size);
		return tchar;
	}

	static __inline wchar_t *A2W(const std::string &str)
	{
		return Convert::A2W(str.c_str());
	}
	static __inline std::wstring A2WS(const std::string &str)
	{
		return Convert::A2WS(str.c_str());
	}

	static __inline std::wstring A2WS(const char *str)
	{
		AutoFree<wchar_t> wc = A2W(str);
		std::wstring ws(wc);
		return ws;
	}

	static unsigned short utf8_to_utf16(char *val)
	{
		std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
		std::u16string dest = convert.from_bytes(val);
		return *(unsigned short *)&dest[0];
	}
	static char *TChar_To_UTF8(const wchar_t *str)
	{
		int nLen = ::WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, NULL, NULL, NULL);
		static char pBuf[0x1000];
		WideCharToMultiByte(CP_UTF8, 0, str, nLen, pBuf, nLen, NULL, NULL);
		return pBuf;
	}
	// AnsiUTF8
	static __inline std::string AnsiToUtf8(const std::string &str)
	{
		int len = ::MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, NULL, 0);

		AutoFree<wchar_t> wstr(len);
		::MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, wstr, len);
		len = ::WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);

		AutoFree<char> utf8(len);
		::WideCharToMultiByte(CP_UTF8, 0, wstr, -1, utf8, len, NULL, NULL);

		std::string result(utf8);

		return result;
	}

	// GBKUTF8
	static __inline std::string GbkToUtf8(const std::string &str)
	{
		int len = ::MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, NULL, 0);

		AutoFree<wchar_t> wstr(len);
		::MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, wstr, len);

		len = ::WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);

		AutoFree<char> utf8(len);
		::WideCharToMultiByte(CP_UTF8, 0, wstr, -1, utf8, len, NULL, NULL);
		std::string result(utf8);

		return result;
	}

	// GB2312UTF8
	static __inline std::string Gb2312ToUtf8(const std::string &str)
	{
		int len = ::MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, NULL, 0);

		AutoFree<wchar_t> wstr(len);
		::MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, wstr, len);
		len = ::WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);

		AutoFree<char> utf8(len);
		::WideCharToMultiByte(CP_UTF8, 0, wstr, -1, utf8, len, NULL, NULL);
		std::string result(utf8);

		return result;
	}

	// UTF8Ansi
	static __inline std::string Utf8ToAnsi(const std::string &str)
	{
		int len = ::MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, NULL, 0);

		AutoFree<wchar_t> wstr(len);
		::MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, wstr, len);
		len = ::WideCharToMultiByte(CP_ACP, 0, wstr, -1, NULL, 0, NULL, NULL);

		AutoFree<char> ansi(len);
		::WideCharToMultiByte(CP_ACP, 0, wstr, -1, ansi, len, NULL, NULL);
		std::string result(ansi);

		return result;
	}

	// UTF8GBK
	static __inline std::string Utf8ToGbk(const std::string &str)
	{
		int len = ::MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, NULL, 0);

		AutoFree<wchar_t> wstr(len);
		::MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, wstr, len);
		len = ::WideCharToMultiByte(CP_ACP, 0, wstr, -1, NULL, 0, NULL, NULL);

		AutoFree<char> gbk(len);
		::WideCharToMultiByte(CP_ACP, 0, wstr, -1, gbk, len, NULL, NULL);
		std::string result(gbk);

		return result;
	}

	// UTF8GB2312
	static __inline std::string Utf8ToGb2312(const std::string &str)
	{
		int len = ::MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, NULL, 0);

		AutoFree<wchar_t> wstr(len);
		::MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, wstr, len);
		len = ::WideCharToMultiByte(CP_ACP, 0, wstr, -1, NULL, 0, NULL, NULL);

		AutoFree<char> gb2312(len);
		::WideCharToMultiByte(CP_ACP, 0, wstr, -1, gb2312, len, NULL, NULL);
		std::string result(gb2312);

		return result;
	}

	// UTF16UTF8
	static __inline std::string Utf16ToUtf8(const std::wstring &wstr)
	{
		int len = ::WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, NULL, 0, NULL, NULL);

		AutoFree<char> utf8(len);
		::WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), -1, utf8, len, NULL, NULL);
		std::string result(utf8);

		return result;
	}

	// UTF8UTF16
	static __inline std::wstring Utf8ToUtf16(const std::string &str)
	{
		int len = ::MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, NULL, 0);

		AutoFree<wchar_t> wstr(len);
		::MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, wstr, len);
		std::wstring result(wstr);

		return result;
	}

	// AnsiUnicode
	static std::wstring AnsiToUnicode(const std::string &ansiStr)
	{
		int len = MultiByteToWideChar(CP_ACP, 0, ansiStr.c_str(), ansiStr.length(), NULL, 0);

		AutoFree<wchar_t> unicodeStr(len + 1);

		MultiByteToWideChar(CP_ACP, 0, ansiStr.c_str(), ansiStr.length(), unicodeStr, len);
		std::wstring result(unicodeStr);

		return result;
	}
	// UnicodeAnsi
	static std::string UnicodeToAnsi(const std::wstring &unicodeStr)
	{
		int len = WideCharToMultiByte(CP_ACP, 0, unicodeStr.c_str(), unicodeStr.length(), NULL, 0, NULL, NULL);

		AutoFree<char> ansiStr(len + 1);
		WideCharToMultiByte(CP_ACP, 0, unicodeStr.c_str(), unicodeStr.length(), ansiStr, len, NULL, NULL);
		std::string result(ansiStr);

		return result;
	}

	static std::wstring Utf8ToUnicode(const std::string &utf8Str)
	{
		int len = MultiByteToWideChar(CP_UTF8, 0, utf8Str.c_str(), utf8Str.length(), NULL, 0);

		AutoFree<wchar_t> unicodeStr(len + 1);
		MultiByteToWideChar(CP_UTF8, 0, utf8Str.c_str(), utf8Str.length(), unicodeStr, len);
		std::wstring result(unicodeStr);

		return result;
	}

	static std::string UnicodeToUtf8(const std::wstring &unicodeStr)
	{
		int len = WideCharToMultiByte(CP_UTF8, 0, unicodeStr.c_str(), unicodeStr.length(), NULL, 0, NULL, NULL);

		AutoFree<char> utf8Str(len + 1);
		WideCharToMultiByte(CP_UTF8, 0, unicodeStr.c_str(), unicodeStr.length(), utf8Str, len, NULL, NULL);
		std::string result(utf8Str);

		return result;
	}

	static std::string string_to_utf8(const std::string &str)
	{
		int nwLen = ::MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, NULL, 0);

		AutoFree<wchar_t> pwBuf(nwLen + 1);

		::MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.length(), pwBuf, nwLen);

		int nLen = ::WideCharToMultiByte(CP_UTF8, 0, pwBuf, -1, NULL, NULL, NULL, NULL);

		AutoFree<char> pBuf(nLen + 1);

		::WideCharToMultiByte(CP_UTF8, 0, pwBuf, nwLen, pBuf, nLen, NULL, NULL);
		std::string retStr(pBuf);

		return retStr;
	}
	static std::string utf8_to_string(const std::string &str)
	{
		int nwLen = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, NULL, 0);

		AutoFree<wchar_t> pwBuf(nwLen + 1);

		MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), pwBuf, nwLen);

		int nLen = WideCharToMultiByte(CP_ACP, 0, pwBuf, -1, NULL, NULL, NULL, NULL);

		AutoFree<char> pBuf(nLen + 1);
		WideCharToMultiByte(CP_ACP, 0, pwBuf, nwLen, pBuf, nLen, NULL, NULL);

		std::string retStr(pBuf);

		return retStr;
	}

	// ַBase64
	static __inline std::string ToBase64(const std::string &input)
	{
		static const std::string base64_chars =
			"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
			"abcdefghijklmnopqrstuvwxyz"
			"0123456789+/";

		std::string output;
		int char_count = 0;
		unsigned char char_array_3[3];
		unsigned char char_array_4[4];

		for (const auto &c : input)
		{
			char_array_3[char_count++] = c;
			if (char_count == 3)
			{
				char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
				char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
				char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
				char_array_4[3] = char_array_3[2] & 0x3f;

				for (const auto &i : char_array_4)
				{
					output += base64_chars[i];
				}
				char_count = 0;
			}
		}

		if (char_count)
		{
			for (auto i = char_count; i < 3; i++)
			{
				char_array_3[i] = '\0';
			}

			char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
			char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
			char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
			char_array_4[3] = char_array_3[2] & 0x3f;

			for (auto i = 0; i < char_count + 1; i++)
			{
				output += base64_chars[char_array_4[i]];
			}

			while (char_count++ < 3)
			{
				output += '=';
			}
		}

		return output;
	}

	// Base64
	static __inline std::string FromBase64(const std::string &input)
	{
		static const std::string base64_chars =
			"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
			"abcdefghijklmnopqrstuvwxyz"
			"0123456789+/";

		std::string output;
		int char_count = 0;
		unsigned char char_array_4[4];
		unsigned char char_array_3[3];

		for (const auto &c : input)
		{
			if (c == '=')
			{
				break;
			}

			char_array_4[char_count++] = base64_chars.find(c);
			if (char_count == 4)
			{
				char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
				char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
				char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

				std::copy(char_array_3, char_array_3 + 3, std::back_inserter(output));
				char_count = 0;
			}
		}

		if (char_count)
		{
			for (auto i = char_count; i < 4; i++)
			{
				char_array_4[i] = 0;
			}

			char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
			char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
			char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];

			std::copy(char_array_3, char_array_3 + char_count - 1, std::back_inserter(output));
		}

		return output;
	}

	static __inline int ToInt32(const std::string &input)
	{
		return atoi(input.c_str());
	}
	static __inline __int64 ToInt64(const std::string &input)
	{
		return atoll(input.c_str());
	}
	static __inline double ToDouble(const std::string &input)
	{
		return atof(input.c_str());
	}
	static __inline float ToFloat(const std::string &input)
	{
		return atof(input.c_str());
	}
#define ToDouble ToFloat
};
